/*
 * OccurrencePattern.hpp
 *
 * Copyright 2012 Fabian Wenzelmann
 *
 * This file is part of Recognition-Procedures-for-Boolean-Functions.
 *
 * Recognition-Procedures-for-Boolean-Functions is free software: you
 * can redistribute it and/or modify it under the terms of the
 * GNU General Public License as published by the Free Software Foundation,
 * either version 3 of the License, or (at your option) any later version.
 *
 * Recognition-Procedures-for-Boolean-Functions is distributed in the hope
 * that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
 * Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Recognition-Procedures-for-Boolean-Functions.
 *
 * If not, see <http://www.gnu.org/licenses/>.
 */

#ifndef OCCURRENCEPATTERN_HPP_
#define OCCURRENCEPATTERN_HPP_

#include <string>
#include <sstream>
#include <iostream>
#include <set>

namespace bfr {

/**
 * Class for occurrence patterns.
 *
 * For the definition of occurrence patterns see
 * <a href="http://www.informatik.uni-freiburg.de/~ki/papers/smaus-tr230.pdf">
 * Smaus 2007
 * </a>
 *
 * An occurrence pattern in C++ is just an ordered multiset of
 * <code>size_t</code> elements.
 *
 * It is required that the iterator returns the elements in the
 * ordered sequence.
 *
 * The elements are stored in a
 * <a href="http://www.cplusplus.com/reference/stl/multiset/">
 * std::multiset
 * </a>.
 */
class OccurrencePattern {

    protected:
        /**
         * Container type that holds the elements.
         */
        typedef std::multiset<size_t> container_t;

    public:
        /**
         * The iterator type.
         */
        typedef container_t::const_iterator const_iterator;

        /**
         * Constructor.
         *
         * Create a new occurrence pattern for the variable with the id.
         */
        explicit OccurrencePattern(size_t vID);

        /**
         * Constructor.
         *
         * Creates a new occurrence pattern for the variable with the id
         * and an initial size.
         *
         * The initial size will be ignored at the moment, but maybe if
         * we change the implementation it can help.
         */
        OccurrencePattern(size_t vID, size_t initialSize);

        /**
         * Copy constructor.
         *
         * This constructor creates a copy of the multiset.
         */
        OccurrencePattern(const OccurrencePattern &other);

        /**
         * Destructor.
         */
        ~OccurrencePattern();

        /**
         * Return an iterator to the beginning.
         *
         * The iterators must return the elements
         * in <i>ordered</i> sequence.
         *
         * @return An iterator to the beginning.
         */
        const_iterator begin() const;

        /**
         * Return an iterator to the end.
         *
         * The iterators must return the elements
         * in <i>ordered</i> sequence.
         *
         * @return An iterator to the end.
         */
        const_iterator end() const;

        /**
         * Add an occurrence to this pattern.
         *
         * Adds an occurrence to this pattern for a clause
         * with size <code>variableCount</code>.
         */
        void addOccurrence(const size_t variableCount);

        /**
         * Return the size of the multiset.
         *
         * @return Number of elements in the multiset.
         */
        size_t size() const;

        /**
         * Return the id of the pattern's variable.
         *
         * Return the id of the variable this occurrence pattern
         * was created for.
         */
        size_t getVariableId() const;

        /**
         * Compare this pattern to another pattern.
         *
         * This method implements a comparison according to the
         * \f$\succeq\f$ order as defined in
         * <a href="http://www.informatik.uni-freiburg.de/~ki/papers/smaus-tr230.pdf">
         * Smaus 2007
         * </a>.
         *
         * This method returns a value \f$< 0 \f$ if \f$this \prec other\f$,
         * a value \f$> 0\f$ if \f$this \succ other\f$ and
         * \f$0\f$ if \f$this = other\f$.
         *
         * @return Comparison value.
         */
        short compare(const OccurrencePattern &other) const;

        /**
         * Compare two occurrence patterns.
         *
         * @return <code>true</code> if \f$this = other\f$.
         */
        bool operator ==(const OccurrencePattern &other) const;

        /**
         * Compare two occurrence patterns.
         *
         * @return <code>true</code> if \f$this \neq other\f$.
         */
        bool operator !=(const OccurrencePattern &other) const;

        /**
         * Compare two occurrence patterns.
         *
         * @return <code>true</code> if \f$this \prec other\f$.
         */
        bool operator <(const OccurrencePattern &other) const;

        /**
         * Compare two occurrence patterns.
         *
         * @return <code>true</code> if \f$this \succ other\f$.
         */
        bool operator >(const OccurrencePattern &other) const;

        /**
         * Compare two occurrence patterns.
         *
         * @return <code>true</code> if \f$this \preceq other\f$.
         */
        bool operator <=(const OccurrencePattern &other) const;

        /**
         * Compare two occurrence patterns.
         *
         * @return <code>true</code> if \f$this \succeq other\f$.
         */
        bool operator >=(const OccurrencePattern &other) const;

        /**
         * Function to compare two occurrence patterns.
         *
         * It simply returns <code>o1 > o2</code>.
         *
         * @return <code>true</code> if \f$o_1 \succ o_2\f$.
         */
        inline static bool compareImportance(const OccurrencePattern *o1,
                const OccurrencePattern *o2) {
            return o1->operator >(*o2);
        }

        /**
         * Write pattern to a stream.
         *
         * @return The argument <code>out</code>.
         */
        friend std::ostream& operator<<(std::ostream &out,
                const OccurrencePattern &op) {
            out << '{';
            bool first = true;
            for (const_iterator it = op.begin();
                    it != op.end();
                    it++) {
                if (first)
                    first = false;
                else
                    out << ", ";
                out << *it;
            }
            out << '}';
            return out;
        }

        /**
         * Return a string representation of this pattern.
         *
         * @return A human readable version of this pattern.
         */
        std::string asString() const;

    protected:
        // the variable id
        const size_t variableID;
        // stores the elements
        container_t elements;
};

}

#endif  // OCCURRENCEPATTERN_HPP_
